/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package extension.room.maubinh;

import com.smartfoxserver.v2.entities.Room;
import com.smartfoxserver.v2.entities.User;
import extension.game.room.Game;
import extension.game.room.Player;
import extension.game.zone.Flag;
import extension.maubinh.handler.MauBinhSet;
import java.util.LinkedList;
import java.util.List;
import log.Debug;

/**
 *
 * @author daz
 */
public class MauBinhGame extends Game {

    public static final int DO_NOTHING = 0;
    public static final int READY_COUNT = 1;
    public static final int SORT_CARD = 2;
    public static final int SHOW_RESULT = 3;
    public static final int PREPARE_NEW_MATCH = 4;
    private int gameState;
    private MauBinhExtension mauBinhExtension;
    private MauBinhPlayer[] listPlayers;
    private MauBinhResponse mauBinhResponse;
    private long startTime;
    private boolean isDealed;
    private boolean isSendReady;
    private boolean calculateResult;
    private int timeToReady;
    private boolean isResetTable;
    private int numberFinish;

    MauBinhGame(MauBinhExtension mauBinhExtension, int roomId) {
        super(mauBinhExtension.getParentRoom(), roomId);
        this.mauBinhExtension = mauBinhExtension;
        numberDealCard = 13;
        listPlayers = new MauBinhPlayer[maxPlayer];
        this.mauBinhResponse = mauBinhExtension.getResponse();
        gameState = DO_NOTHING;
        isResetTable = true;
        if (Debug.isDebug) {
            betMoney = 500;
        }
    }

    @Override
    public MauBinhPlayer addPlayer(String name, long money, User user) {
        MauBinhPlayer player = new MauBinhPlayer(name, money, numberPlayers);
        player.setUser(user);
        if (numberPlayings <= 0 || numberPlayers <= 0) {
            isPlay = false;
        }
        if (numberPlayers < maxPlayer) {
            int seatPos = -1;
            for (int i = 0; i < maxPlayer; i++) {
                if (listPlayers[i] == null) {
                    seatPos = i;
                    listPlayers[seatPos] = player;
                    listPlayers[seatPos].setSeatPos(seatPos);
                    if (isPlay) {
                        if (isDealed) {
                            listPlayers[seatPos].setState(MauBinhPlayer.NOT_READY);
                        }
                    } else {
                        numberPlayings++;
                    }
                    break;
                }
            }
            if (numberPlayings == 1 && seatPos > -1) {
                listPlayers[seatPos].isHost = true;
                tableHost = seatPos;
            }
            numberPlayers++;
        } else {
            player.setSeatPos(-1);
        }
        if (!isPlay && listPlayers[tableHost] == null) {
            for (int i = 0; i < maxPlayer; i++) {
                if (listPlayers[i] != null) {
                    listPlayers[i].isHost = true;
                    tableHost = i;
                    break;
                }
            }
        }
        addTableInfo();
        Debug.d("number playing when add:" + numberPlayings);
        return player;
    }

    @Override
    protected void addTableInfo() {
        Debug.d("table info ");
        List<String> listPlayerNames = new LinkedList<String>();
        List<Integer> listPlayerPositions = new LinkedList<Integer>();
        for (int i = 0; i < listPlayers.length; i++) {
            if (listPlayers[i] != null) {
                if (listPlayers[i].getState() != MauBinhPlayer.PLAYING) {
                    listPlayerPositions.add(0);
                } else {
                    listPlayerPositions.add(1);
                }
                listPlayerNames.add(listPlayers[i].getName());
            } else {
                listPlayerPositions.add(-1);
                listPlayerNames.add("0");
            }
        }

        Debug.d("player name :" + listPlayerNames.toString());
        Debug.d("player pos :" + listPlayerPositions.toString());
        room.setProperty(Flag.NUMBER_PLAYER, numberPlayings);
        room.setProperty(Flag.ROOM_PLAYER_NAME, listPlayerNames);
        room.setProperty(Flag.ROOM_PLAYER_POS, listPlayerPositions);
        Room lobbyRoom = mauBinhExtension.getParentZone().getRoomByName("The Lobby");
        Debug.d("lobby room :" + lobbyRoom.getUserList().toString());
        List<User> listSend = lobbyRoom.getUserList();
        Debug.d("list in lobby:" + listSend.toString());
        for (User u : listSend) {
            String groupView = (String) u.getProperty(Flag.GROUP_NAME);
            Debug.d("group view :" + groupView);
            if (groupView.equals(room.getGroupId())) {
                Debug.d("send update to :" + u.getName());
                mauBinhResponse.sendTableInfo(room.getName(), listPlayerNames, listPlayerPositions, lobbyRoom.getUserList());
            }
        }

    }

    @Override
    public void sendTableInfo(List<String> listNames, List<Long> listMoneys, List<Integer> listStates, Player player, User user) {
        this.mauBinhResponse.sendTableInfo(listNames, listMoneys, listStates, betMoney,
                isPlay, tableHost, player.getSeatPos(), player.getTotalMoney(), user);
//        if (isPlay) {
//            for (int i = 0; i < maxPlayer; i++) {
//                MauBinhPlayer p = listPlayers[i];
//                if (p != null && p.getState() == MauBinhPlayer.PLAYING) {
//                    if (p.getShowPhomOrder() >= 0) {
//                        phomResponse.sendTableState(p.getListEatCards(), p.getListFightCard(), p.getSeatPos(), p.getListPhom(), user);
//                    } else {
//                        phomResponse.sendTableState(p.getListEatCards(), p.getListFightCard(), p.getSeatPos(), null, user);
//                    }
//                }
//            }
//        } else {
//            if (isHostTimeOut) {
//                phomResponse.sendDeleteHostTimeOut(tableHost);
//                setIsHostTimeOut(false);
//            }
//        }
    }

    @Override
    public void updateReadyState() {
        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null && listPlayers[i].getState() == MauBinhPlayer.READY) {
                listPlayers[i].setState(MauBinhPlayer.NOT_READY);
                mauBinhResponse.sendReadyState(i, MauBinhPlayer.NOT_READY, 1);
            }
        }
    }

    @Override
    public long removePlayer(int leaveId) {
        long playerMoney = 0;
        numberPlayers--;
        if (listPlayers[leaveId] != null) {
            playerMoney = listPlayers[leaveId].getMoney() + listPlayers[leaveId].getTotalMoney();
            listPlayers[leaveId] = null;
            numberPlayings--;
            Debug.d("number playing when remove :" + numberPlayings);
            if (leaveId == tableHost) {
                updateTableHost();
            }
            if (isPlay) {
                if (isDealed) {
                    penaltyMoney += betMoney * 5;
                }
            }

            if (numberPlayings < 2) {
                resetTableState();
            }
        }
        addTableInfo();
        return playerMoney;
    }

    private void resetTableState() {
        isPlay = false;
        isDealed = false;
        isSendReady = false;
        gameState = DO_NOTHING;
        calculateResult = false;
        isResetTable = true;
    }

    @Override
    public void sendTimeCount(int host) {
        this.mauBinhResponse.sendTimeCount(host);
    }

    @Override
    public void updateTableHost() {
        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null) {
                tableHost = i;
                listPlayers[i].isHost = true;
                if (isPlay) {
                    mauBinhResponse.sendUpdateTableHost(i, 1);
                } else {
                    mauBinhResponse.sendUpdateTableHost(i, 0);
                    updateReadyState();
                }
                break;
            }
        }
    }

    @Override
    public void sendUpdateTableHost(int newHost, int isContinue) {
        this.mauBinhResponse.sendUpdateTableHost(newHost, isContinue);
    }

    @Override
    public int changePlayerState(int readyId) {
        if (listPlayers[readyId] != null) {
            return listPlayers[readyId].changeState();
        }
        return -1;
    }

    @Override
    public int countNumberReady() {
        int result = 0;
        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null && listPlayers[i].getState() == Player.READY) {
                result++;
            }
        }
        return result;
    }

    private int getCard() {
        int cardId = dealer.nextCard();
        if (cardId == -1) {
            for (int i = 0; i < maxPlayer; i++) {
                if (listPlayers[i] != null) {
                    mauBinhExtension.getApi().kickUser(listPlayers[i].getUser(), null, "", 0);
                    Debug.d("out of dealer index of phom");
                    listPlayers[i] = null;
                }

            }
        }
        return cardId;
    }

    @Override
    public void dealCard() {
        dealer.shuffleCard();
        List<Integer> dealPos = new LinkedList<Integer>();
        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null) {
                listPlayers[i].resetCard();
                for (int j = 0; j < numberDealCard; j++) {
                    listPlayers[i].addCard(getCard(), MauBinhPlayer.NORMAL_CARD);
                }
                dealPos.add(1);
            } else {
                dealPos.add(0);
            }
        }

        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null) {
                listPlayers[i].setState(MauBinhPlayer.PLAYING);
                listPlayers[i].initCardBranh();
                mauBinhResponse.sendDealCard(listPlayers[i].getListCardIds(), dealPos, listPlayers[i].isRightOrder(), listPlayers[i].getUser());
            }
        }
        isDealed = true;
        isSendReady = false;
        calculateResult = false;
    }

    @Override
    public void nextTurn() {
    }

    @Override
    protected void checkAllowPlay() {
        if (!Debug.isDebug) {
            for (int i = 0; i < maxPlayer; i++) {
                if (listPlayers[i] != null && listPlayers[i].getMoney() < betMoney * 5) {
                    mauBinhResponse.sendPlayerKick(listPlayers[i].getName(), listPlayers[i].getSeatPos(), listPlayers[i].getUser());
                }
            }
        } else {
            for (int i = 0; i < maxPlayer; i++) {
                if (listPlayers[i] != null && listPlayers[i].getMoney() < 0) {
                    mauBinhResponse.sendPlayerKick(listPlayers[i].getName(), listPlayers[i].getSeatPos(), listPlayers[i].getUser());
                }
            }
        }
    }

    @Override
    protected void sendPlayerKick(String name, int seatPos, User user) {
        this.mauBinhResponse.sendPlayerKick(name, seatPos, user);
    }

    @Override
    public void updateDatabase() {
        if (!Debug.isDebug) {
            for (int i = 0; i < maxPlayer; i++) {
                if (listPlayers[i] != null) {
                    this.mauBinhExtension.getDatabase().updateMoneyJoin(mauBinhExtension.getRoomPrefix(), listPlayers[i].getName(), listPlayers[i].getMoney());
                }
            }
        }

    }

    @Override
    public MauBinhPlayer[] getListPlayers() {
        return listPlayers;
    }

    @Override
    protected void sendTableInfo(String roomName, List<String> listNames, List<Integer> listPos, List<User> listUser) {
        this.mauBinhResponse.sendTableInfo(roomName, listNames, listPos, listUser);
    }

    private void setPlayerState(int state) {
        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null) {
                listPlayers[i].setState(MauBinhPlayer.PLAYING);
            }
        }
    }

    @Override
    public void doLoop() {
        if (gameState == READY_COUNT) {
            if (numberPlayings <= 1) {
                gameState = DO_NOTHING;
            } else if (!isSendReady) {
                timeToReady = 10;
                startTime = System.currentTimeMillis();
                mauBinhResponse.sendReadyPlay(tableHost, timeToReady);
                isPlay = true;
                isSendReady = true;
                setPlayerState(MauBinhPlayer.PLAYING);
            } else if (System.currentTimeMillis() - startTime > timeToReady * 1000) {
                gameState = SORT_CARD;
            }

        } else if (gameState == SORT_CARD) {
            if (!isDealed) {
                dealCard();
                startTime = System.currentTimeMillis();
            } else {
                if (System.currentTimeMillis() - startTime > 30000) {
                    gameState = SHOW_RESULT;
                }
            }
        } else if (gameState == SHOW_RESULT) {
            if (!calculateResult) {
                onMatchResult();
                numberFinish = 0;
                calculateResult = true;
                startTime = System.currentTimeMillis();
            } else {
                if (System.currentTimeMillis() - startTime > 40000) {
                    gameState = READY_COUNT;
                    isDealed = false;
                    isSendReady = false;
                    calculateResult = false;
                    isPlay = false;
                }
            }
        }
    }

    private void onMatchResult() {
        List<Integer> listPlayerCards = new LinkedList<Integer>();
        List<Integer> listCardPos = new LinkedList<Integer>();
        List<Integer> listBranchType1 = new LinkedList<Integer>();
        List<Integer> listBranchType2 = new LinkedList<Integer>();
        List<Integer> listBranchType3 = new LinkedList<Integer>();
        List<Long> listTotalMoneyResult = new LinkedList<Long>();

        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null) {
                listPlayerCards.addAll(listPlayers[i].getListCardIds());
                listCardPos.add(i);
                boolean isRightOrder = listPlayers[i].isRightOrder();
                if (isRightOrder) {
                    listBranchType1.add(listPlayers[i].getCardBranchType(1));
                    listBranchType2.add(listPlayers[i].getCardBranchType(2));
                    listBranchType3.add(listPlayers[i].getCardBranchType(3));
                } else {
                    listBranchType1.add(MauBinhSet.BINH_THUNG);
                    listBranchType2.add(MauBinhSet.BINH_THUNG);
                    listBranchType3.add(MauBinhSet.BINH_THUNG);
                }
            } else {
                listBranchType1.add(-1);
                listBranchType2.add(-1);
                listBranchType3.add(-1);
            }
        }

        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null) {
                MauBinhPlayer p = listPlayers[i];
                p.setTotalMoneyResult(0);
                List<Long> branchResult1 = calculateResult(i, 1);
                List<Long> branchResult2 = calculateResult(i, 2);
                List<Long> branchResult3 = calculateResult(i, 3);
                p.setBranchResult1(branchResult1);
                p.setBranchResult2(branchResult2);
                p.setBranchResult3(branchResult3);
//                mauBinhResponse.sendResult(
//                        branchResult1, branchResult2, branchResult3,
//                        p.getMoneyResult(1), p.getMoneyResult(2), p.getMoneyResult(3),
//                        listBranchType1, listBranchType2, listBranchType3,
//                        listPlayerCards, listCardPos, p.getUser());
            }
        }

        for (int i = 0; i < maxPlayer; i++) {
            MauBinhPlayer p = listPlayers[i];
            if (p != null) {
                listTotalMoneyResult.add(p.getTotalMoneyResult());
            } else {
                listTotalMoneyResult.add(0l);
            }
        }

        for (int i = 0; i < maxPlayer; i++) {
            MauBinhPlayer p = listPlayers[i];
            if (p != null) {
                mauBinhResponse.sendResult(
                        p.getBranchResult1(), p.getBranchResult2(), p.getBranchResult3(),
                        p.getMoneyResult(1), p.getMoneyResult(2), p.getMoneyResult(3),
                        listBranchType1, listBranchType2, listBranchType3,
                        listTotalMoneyResult,
                        listPlayerCards, listCardPos, p.getUser());
            }
        }
    }

    private List<Long> calculateResult(int playerId, int branchId) {
        List<Long> branchResult = new LinkedList<Long>();
        int branchRank = listPlayers[playerId].getCardBranhRank(branchId);
        long moneyResult = 0;
        for (int j = 0; j < maxPlayer; j++) {
            if (playerId != j && listPlayers[j] != null && listPlayers[j].getState() == MauBinhPlayer.PLAYING) {
                int rankCheck = listPlayers[j].getCardBranhRank(branchId);
                if (rankCheck > branchRank) {
                    branchResult.add(betMoney);
                    moneyResult += betMoney;
                } else {
                    branchResult.add(-betMoney);
                    moneyResult -= betMoney;
                }
            } else {
                branchResult.add(0l);
            }
        }
        listPlayers[playerId].setBranchMoneyWin(branchId, moneyResult);
        return branchResult;
    }

    public void setGameState(int gameState) {
        this.gameState = gameState;
    }

    public int getGameState() {
        return gameState;
    }

    @Override
    public void doReady() {
        setIsHostTimeOut(true);
        mauBinhResponse.sendTimeCount(tableHost);
    }

    @Override
    public void updateTableInfo(List<String> listNames, List<Long> listMoneys, List<Integer> listStates, Player player) {
        sendTableInfo(listNames, listMoneys, listStates, player, player.getUser());
        updateNumberPlaying();
        if (numberPlayings >= 1 && player.getSeatPos() >= 0) {
            sendUpdateTable(player.getUser(), player);
            sendUpdate();
        }
        if (numberPlayings >= 2 && (gameState == READY_COUNT || gameState == DO_NOTHING)) {
            if (!isSendReady) {
                if (isResetTable) {
                    timeToReady = 20;
                    isResetTable = false;
                    isPlay = true;
                    startTime = System.currentTimeMillis();
                    gameState = READY_COUNT;
                } else {
                    timeToReady = 10;
                }
                mauBinhResponse.sendReadyPlay(tableHost, timeToReady);
                isDealed = false;
                isSendReady = true;
            } else {
                long timeRemain = (timeToReady * 1000 - System.currentTimeMillis() + startTime) / 1000;
                mauBinhResponse.sendReadyPlay(tableHost, timeRemain);
            }
            player.setState(MauBinhPlayer.PLAYING);

        }
    }

    private void sendUpdateTable(User user, Player player) {
        List<User> listSend = room.getUserList();
        listSend.remove(user);
        mauBinhResponse.sendUpdatePlayers(user.getName(), player.getMoney(), player.getSeatPos(), listSend);
    }

    private void sendUpdate() {
        String groupName = room.getGroupId();
        Room lobbyRoom = mauBinhExtension.getParentZone().getRoomByName("The Lobby");
        List<User> listSend = lobbyRoom.getUserList();
        for (User u : listSend) {
            String groupView = (String) u.getProperty(Flag.GROUP_NAME);
            if (groupView.equals(groupName)) {
                mauBinhResponse.sendUpdateTable(room.getName(), numberPlayings, room.getGroupId(), betMoney, u);
            }
        }
    }

    @Override
    public void updateNumberPlaying() {
        numberPlayings = 0;
        for (int i = 0; i < maxPlayer; i++) {
            if (listPlayers[i] != null) {
                numberPlayings++;
            }
        }
    }

    public boolean isIsDealed() {
        return isDealed;
    }

    @Override
    public void updateNumberInRoom() {
        numberInRooms = 0;
        for (int i = 0; i < maxPlayer; i++) {
            numberInRooms++;
        }
    }

    public void doPlayerFinishShowResult() {
        numberFinish++;
        if (numberFinish == numberPlayings) {
            gameState = READY_COUNT;
            isDealed = false;
            isSendReady = false;
            calculateResult = false;
            isPlay = false;
            numberFinish = 0;
        }
    }

    public boolean exchangeCard(int playerPos, int cardId1, int branch1, int cardId2, int branch2) {
        MauBinhPlayer p = listPlayers[playerPos];
        if (p != null) {
            return p.exchangeCard(cardId1, branch1, cardId2, branch2);
        }
        return false;
    }

    public MauBinhPlayer getPlayer(int playerPos) {
        return listPlayers[playerPos];
    }
}
